package org.ciallo.simplemusicplayer.data.dao;

import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData;
import androidx.room.*;
import org.ciallo.simplemusicplayer.data.model.Song;
import org.ciallo.simplemusicplayer.util.Constants;

import java.util.List;

/**
 * @author Jukomu
 * @Description: Song 实体的 数据访问对象 (DAO)
 * @Package: org.ciallo.simplemusicplayer.data.dao
 * @Project: SimpleMusicPlayer
 * @name: SongDao
 * @Date: 2025/5/29-05:35
 * @Filename: SongDao
 */
@Dao
public interface SongDao {

    /**
     * 插入一首歌曲。如果已存在，则替换。
     *
     * @param song 要插入的歌曲。
     */
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertSong(Song song);

    /**
     * 插入多首歌曲。如果某首歌曲已存在，则替换。
     *
     * @param songs 要插入的歌曲列表。
     */
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertAllSongs(List<Song> songs);

    /**
     * 更新一首歌曲。
     *
     * @param song 要更新的歌曲。
     */
    @Update
    void updateSong(Song song);

    /**
     * 删除一首歌曲。
     *
     * @param song 要删除的歌曲。
     */
    @Delete
    void deleteSong(Song song);

    /**
     * 根据ID删除一首歌曲。
     *
     * @param songId 要删除的歌曲ID。
     */
    @Query("DELETE FROM songs WHERE id = :songId")
    void deleteSongById(long songId);

    /**
     * 删除所有歌曲。
     */
    @Query("DELETE FROM songs")
    void deleteAllSongs();

    /**
     * 根据ID获取一首歌曲。
     *
     * @param songId 歌曲ID。
     * @return LiveData 包装的歌曲对象，如果不存在则为null。
     */
    @Query("SELECT * FROM songs WHERE id = :songId LIMIT 1")
    LiveData<Song> getSongById(long songId);

    /**
     * 获取所有歌曲，按标题拼音升序排列。
     *
     * @return LiveData 包装的歌曲列表。
     */
    @Query("SELECT * FROM songs ORDER BY title_pinyin ASC")
    LiveData<List<Song>> getAllSongsSortedByPinyin();

    /**
     * 获取所有歌曲，按添加日期降序排列。
     *
     * @return LiveData 包装的歌曲列表。
     */
    @Query("SELECT * FROM songs ORDER BY date_added DESC")
    LiveData<List<Song>> getAllSongsSortedByDateAdded();

    /**
     * 获取数据库中所有歌曲的文件路径列表。
     * 注意：这个查询可能返回大量数据，如果歌曲非常多，需要考虑性能。
     * 对于增量更新，通常在后台线程执行。
     *
     * @return 包含所有歌曲文件路径的列表。
     */
    @Query("SELECT path FROM songs")
    List<String> getAllSongPathsFromDb(); // 改为返回 List<String> 而不是 LiveData，因为通常在后台一次性查询

    /**
     * 根据文件路径列表删除歌曲。
     *
     * @param paths 要删除的歌曲的文件路径列表。
     * @return 删除的行数。
     */
    @Query("DELETE FROM songs WHERE path IN (:paths)")
    int deleteSongsByPaths(List<String> paths);

    /**
     * 根据文件路径查询歌曲。
     *
     * @param path 文件路径。
     * @return 如果找到则返回 Song 对象，否则返回 null。此方法用于检查特定路径是否存在。
     */
    @Query("SELECT * FROM songs WHERE path = :path LIMIT 1")
    Song getSongByPath_internal(String path); // _internal 后缀表示这是一个同步方法，通常在后台线程调用

    // --- 新增用于动态生成歌手列表的方法 ---

    /**
     * 根据歌手名模糊查询该歌手的所有歌曲，按标题拼音排序。
     * 用于处理 "歌手A/歌手B" 这种情况，当查询 "歌手A" 时也能匹配到。
     * @param artistNameQuery 歌手名查询字符串 (例如 "歌手A")。
     * @return LiveData 包装的歌曲列表。
     */
    @Query("SELECT * FROM songs WHERE artist_name LIKE '%' || :artistNameQuery || '%' ORDER BY title_pinyin ASC")
    LiveData<List<Song>> getSongsByArtistNameLike(String artistNameQuery);

    // --- 新增用于动态生成专辑列表的方法 ---


    /**
     * 查询所有唯一的专辑信息。
     * 包含 albumId, albumName, 代表性的 track artist, 代表性的 album artist, 歌曲数, 封面URI。
     *
     * @return LiveData 包装的 AlbumInfoQueryResult 列表。
     */
    @Query("SELECT " +
            "    s.album_id_room as albumId, " +
            "    s.album_name as albumName, " +
            "    s.artist_name as representativeArtistName, " + // Track artist of one song in the album
            "    s.album_artist as albumArtistLabel, " +     // Album artist from one song in the album
            "    COUNT(s.id) as songCount, " +
            "    s.album_art_uri as albumArtUri " +
            "FROM songs s " +
            "WHERE s.album_name IS NOT NULL AND s.album_name != '' AND s.album_name != '" + Constants.UNKNOWN_STRING + "' " +
            "GROUP BY s.album_id_room, s.album_name " + // 分组以确保专辑唯一性
            "ORDER BY s.album_name ASC")
    LiveData<List<AlbumInfoQueryResult>> getAlbumSummaries();


    /**
     * 同步获取指定专辑ID下的所有歌曲，按音轨号排序。
     * 用于在后台线程中处理。
     * @param albumId 专辑ID (即 Song.albumIdRoom)。
     * @return 歌曲列表。
     */
    @Query("SELECT * FROM songs WHERE album_id_room = :albumId ORDER BY track_number ASC, title_pinyin ASC")
    List<Song> getSongsByAlbumId_internal(long albumId); // <--- 新增同步方法

    /**
     * 根据专辑ID获取该专辑下的所有歌曲，按音轨号排序。
     * @param albumId 专辑ID (即 Song.albumIdRoom)。
     * @return LiveData 包装的歌曲列表。
     */
    @Query("SELECT * FROM songs WHERE album_id_room = :albumId ORDER BY track_number ASC, title_pinyin ASC")
    LiveData<List<Song>> getSongsByAlbumId(long albumId);


    /**
     * 临时数据传输对象 (DTO)，用于从 getAlbumSummaries() 查询接收聚合结果。
     */
    class AlbumInfoQueryResult {
        @ColumnInfo(name = "albumId")
        public long albumId;

        @ColumnInfo(name = "albumName")
        public String albumName;

        // 这个 artistName 仍然是取自 songs 表中该专辑下某一条记录的 artist_name
        // 主要用于在没有 album_artist 时提供一个备选的艺术家名。
        @ColumnInfo(name = "representativeArtistName")
        public String representativeArtistName;

        // 新增：从 songs 表中获取该专辑的 album_artist (取组内一个，假设它们一致)
        @ColumnInfo(name = "albumArtistLabel")
        public String albumArtistLabel;

        @ColumnInfo(name = "songCount")
        public int songCount;

        @ColumnInfo(name = "albumArtUri")
        public String albumArtUri;
    }

    // --- 用于文件夹列表的方法 ---

    /**
     * 获取指定文件夹路径下的所有歌曲（不包括子文件夹内的歌曲），按标题拼音排序。
     * @param folderPath 文件夹的绝对路径。
     * @return LiveData 包装的歌曲列表。
     */
    @Query("SELECT * FROM songs WHERE folder_path = :folderPath ORDER BY title_pinyin ASC")
    LiveData<List<Song>> getSongsInFolderPath(String folderPath);

    /**
     * 同步获取指定文件夹路径下的所有歌曲（不包括子文件夹内的歌曲）。
     * 用于在后台线程中处理，例如计算歌曲数量或传递给 FolderSongsActivity。
     * @param folderPath 文件夹的绝对路径。
     * @return 歌曲列表。
     */
    @Query("SELECT * FROM songs WHERE folder_path = :folderPath ORDER BY title_pinyin ASC")
    List<Song> getSongsInFolderPath_internal(String folderPath); // <--- 新增同步版本

    /**
     * 查询所有唯一的包含歌曲的文件夹路径及其对应的歌曲数量。
     * 结果按文件夹路径升序排列。
     *
     * @return LiveData 包装的 FolderPathWithCount 对象列表。
     */
    @Query("SELECT folder_path, COUNT(id) as song_count FROM songs " +
            "WHERE folder_path IS NOT NULL AND folder_path != '' " + // 确保 folder_path 有效
            "GROUP BY folder_path " +
            "ORDER BY folder_path ASC") // 按路径名排序
    LiveData<List<FolderPathWithCount>> getFolderPathsWithSongCounts();

    /**
     * 临时的内部类/DTO，用于从数据库查询文件夹路径及其对应的歌曲数量。
     */
    class FolderPathWithCount {
        @ColumnInfo(name = "folder_path")
        public String folderPath;

        @ColumnInfo(name = "song_count")
        public int songCount;
    }

    /**
     * 根据关键词搜索歌曲。
     * 搜索范围包括歌曲标题 (title), 歌手名 (artist_name), 专辑名 (album_name)。
     * 使用 LIKE 进行模糊匹配，并按标题拼音排序。
     *
     * @param query 用户输入的搜索查询词。
     * @return LiveData 包装的匹配歌曲列表。
     */
    @Query("SELECT * FROM songs WHERE title LIKE :query OR artist_name LIKE :query OR album_name LIKE :query ORDER BY title_pinyin ASC")
    LiveData<List<Song>> searchSongs(String query); // query 参数需要包含 '%' 通配符

    // --- 用于动态生成歌手列表的新方法 (支持搜索) ---
    /**
     * 获取所有不重复的歌手名和代表性的歌手ID。
     * 如果提供了查询词，则只返回 artist_name 匹配的歌手。
     * 结果初步按 artist_name 排序 (后续在 Repository/ViewModel 中按拼音排序)。
     *
     * @param artistNameQuery (可选) 包含 '%'通配符的歌手名搜索查询词。
     * @return LiveData 包装的 ArtistQueryResult 列表。
     */
    @Query("SELECT DISTINCT artist_name, artist_id_room FROM songs " +
            "WHERE artist_name IS NOT NULL AND artist_name != '' AND artist_name != '" + Constants.UNKNOWN_STRING + "' " + // 排除未知歌手
            "AND (:artistNameQuery IS NULL OR :artistNameQuery = '' OR artist_name LIKE :artistNameQuery) " +
            "ORDER BY artist_name ASC") // 初步排序，拼音排序在Repository/ViewModel
    LiveData<List<ArtistQueryResult>> getDistinctArtistsFiltered(@Nullable String artistNameQuery);


    // --- 用于动态生成专辑列表的新方法 (支持搜索) ---
    /**
     * 查询所有唯一的专辑摘要信息，并支持按专辑名搜索。
     *
     * @param albumNameQuery (可选) 包含 '%'通配符的专辑名搜索查询词。
     * @return LiveData 包装的 AlbumInfoQueryResult 列表。
     */
    @Query("SELECT " +
            "    s.album_id_room as albumId, " +
            "    s.album_name as albumName, " +
            "    s.artist_name as representativeArtistName, " +
            "    s.album_artist as albumArtistLabel, " +
            "    COUNT(s.id) as songCount, " +
            // --- 修改这里，使用 MAX() 来优先选择一个非空的封面URI ---
            "    MAX(s.album_art_uri) as albumArtUri " +
            "FROM songs s " +
            "WHERE s.album_name IS NOT NULL AND s.album_name != '' AND s.album_name != '" + Constants.UNKNOWN_STRING + "' " +
            "AND (:albumNameQuery IS NULL OR :albumNameQuery = '' OR s.album_name LIKE :albumNameQuery) " +
            "GROUP BY s.album_id_room " + // <-- 修改这里，只按 album_id_room 分组
            "ORDER BY LOWER(s.album_name) ASC") // <-- 修改这里，按小写字母排序，更准确
    LiveData<List<AlbumInfoQueryResult>> getAlbumSummariesFiltered(@Nullable String albumNameQuery);


    // --- 用于动态生成文件夹列表的新方法 (支持搜索) ---
    /**
     * 查询所有唯一的包含歌曲的文件夹路径及其对应的歌曲数量，并支持按文件夹名搜索。
     * 结果按文件夹路径升序排列。
     * 注意：这里的 LIKE query 会作用于完整的 folder_path。
     * 如果只想搜索 folderName (路径的最后一部分)，则需要在 Repository 中进一步处理。
     *
     * @param folderPathQuery (可选) 包含 '%'通配符的文件夹路径搜索查询词。
     * @return LiveData 包装的 FolderPathWithCount 对象列表。
     */
    @Query("SELECT folder_path, COUNT(id) as song_count FROM songs " +
            "WHERE folder_path IS NOT NULL AND folder_path != '' " +
            "AND (:folderPathQuery IS NULL OR :folderPathQuery = '' OR folder_path LIKE :folderPathQuery) " + // 按完整路径搜索
            "GROUP BY folder_path " +
            "ORDER BY folder_path ASC")
    LiveData<List<FolderPathWithCount>> getFolderPathsWithCountsFiltered(@Nullable String folderPathQuery);


    // --- 辅助POJO用于歌手查询 (如果ArtistInfo需要的字段不多，可以直接用它) ---
    class ArtistQueryResult {
        @ColumnInfo(name = "artist_name")
        public String artistName;
        @ColumnInfo(name = "artist_id_room")
        public long artistIdRoom; // 代表性的歌手ID
    }

    @Query("SELECT * FROM songs WHERE artist_name IS NOT NULL AND artist_name != '' AND artist_name != '" + Constants.UNKNOWN_STRING + "' " +
            "AND (:query IS NULL OR :query = '' OR artist_name LIKE :query)") // query 是带通配符的
    List<Song> getSongsForArtistAggregation_internal(@Nullable String query); // 同步方法


    /**
     * 获取所有 artist_name 非空且非未知的歌曲，如果提供了查询词，则对 artist_name 进行 LIKE 过滤。
     * 用于歌手列表的聚合。
     *
     * @param artistNameQuery (可选) 包含 '%'通配符的歌手名搜索查询词。
     * @return LiveData 包装的歌曲列表。
     */
    @Query("SELECT * FROM songs WHERE " +
            "artist_name IS NOT NULL AND artist_name != '' AND artist_name != '" + Constants.UNKNOWN_STRING + "' " +
            "AND (:artistNameQuery IS NULL OR :artistNameQuery = '' OR artist_name LIKE :artistNameQuery)")
    LiveData<List<Song>> getSongsForArtistAggregationLiveData(@Nullable String artistNameQuery);

    // --- 新增用于获取不重复文件夹路径的方法 (同步，在后台线程调用) ---
    /**
     * 获取数据库中所有歌曲的不重复文件夹路径列表。
     * @return 包含所有不重复文件夹路径的列表。
     */
    @Query("SELECT DISTINCT folder_path FROM songs WHERE folder_path IS NOT NULL AND folder_path != ''")
    List<String> getDistinctFolderPaths(); // <--- 添加这个方法

}
